﻿using System.Collections.Generic;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Reflection;
using System.Windows.Forms;

namespace System
{
  [DebuggerStepThrough]
  public static class ControlsExtensions
  {
    public static void SetDataSource<T>(this ComboBox cmb, IEnumerable<T> list_DataSource, Expression<Func<T, string>> DisplayMember_, Expression<Func<T, int>> ValueMember_)
    {
      Set_Combo_DataSource(ref cmb, list_DataSource, DisplayMember_, ValueMember_);
    }
    public static void SetDataSource<T>(this ComboBox cmb, IEnumerable<T> list_DataSource, Expression<Func<T, string>> DisplayMember_, Expression<Func<T, short>> ValueMember_)
    {
      Set_Combo_DataSource(ref cmb, list_DataSource, DisplayMember_, ValueMember_);
    }
    public static void SetDataSource<T>(this ComboBox cmb, IEnumerable<T> list_DataSource, Expression<Func<T, string>> DisplayMember_, Expression<Func<T, long>> ValueMember_)
    {
      Set_Combo_DataSource(ref cmb, list_DataSource, DisplayMember_, ValueMember_);
    }
    public static void SetDataSource<T>(this ComboBox cmb, IEnumerable<T> list_DataSource, Expression<Func<T, int>> DisplayMember_, Expression<Func<T, int>> ValueMember_)
    {
      Set_Combo_DataSource(ref cmb, list_DataSource, DisplayMember_, ValueMember_);
    }
    public static void SetDataSource<T>(this ComboBox cmb, IEnumerable<T> list_DataSource, Expression<Func<T, int?>> DisplayMember_, Expression<Func<T, int>> ValueMember_)
    {
      Set_Combo_DataSource(ref cmb, list_DataSource, DisplayMember_, ValueMember_);
    }

    private static void Set_Combo_DataSource<T>(ref ComboBox cmb_, IEnumerable<T> list_DataSource, Expression<Func<T, string>> DisplayMember_, Expression<Func<T, int>> ValueMember_)
    {
      cmb_.DataSource = null;
      cmb_.BeginUpdate();

      cmb_.DataSource = list_DataSource;

      if (list_DataSource != null)
      {
        cmb_.DisplayMember = GetPropertyName(DisplayMember_);
        cmb_.ValueMember = GetPropertyName(ValueMember_);
      }

      cmb_.EndUpdate();
    }
    private static void Set_Combo_DataSource<T>(ref ComboBox cmb_, IEnumerable<T> list_DataSource, Expression<Func<T, string>> DisplayMember_, Expression<Func<T, short>> ValueMember_)
    {
      cmb_.DataSource = null;
      cmb_.BeginUpdate();

      cmb_.DataSource = list_DataSource;

      if (list_DataSource != null)
      {
        cmb_.DisplayMember = GetPropertyName(DisplayMember_);
        cmb_.ValueMember = GetPropertyName(ValueMember_);
      }

      cmb_.EndUpdate();
    }
    private static void Set_Combo_DataSource<T>(ref ComboBox cmb_, IEnumerable<T> list_DataSource, Expression<Func<T, string>> DisplayMember_, Expression<Func<T, long>> ValueMember_)
    {
      cmb_.DataSource = null;
      cmb_.BeginUpdate();

      cmb_.DataSource = list_DataSource;

      if (list_DataSource != null)
      {
        cmb_.DisplayMember = GetPropertyName(DisplayMember_);
        cmb_.ValueMember = GetPropertyName(ValueMember_);
      }

      cmb_.EndUpdate();
    }
    private static void Set_Combo_DataSource<T>(ref ComboBox cmb_, IEnumerable<T> list_DataSource, Expression<Func<T, int>> DisplayMember_, Expression<Func<T, int>> ValueMember_)
    {
      cmb_.DataSource = null;
      cmb_.BeginUpdate();

      cmb_.DataSource = list_DataSource;

      if (list_DataSource != null)
      {
        cmb_.DisplayMember = GetPropertyName(DisplayMember_);
        cmb_.ValueMember = GetPropertyName(ValueMember_);
      }

      cmb_.EndUpdate();
    }
    private static void Set_Combo_DataSource<T>(ref ComboBox cmb_, IEnumerable<T> list_DataSource, Expression<Func<T, int?>> DisplayMember_, Expression<Func<T, int>> ValueMember_)
    {
      cmb_.DataSource = null;
      cmb_.BeginUpdate();

      cmb_.DataSource = list_DataSource;

      if (list_DataSource != null)
      {
        cmb_.DisplayMember = GetPropertyName(DisplayMember_);
        cmb_.ValueMember = GetPropertyName(ValueMember_);
      }

      cmb_.EndUpdate();
    }

    private static string GetPropertyName<T, K>(Expression<Func<T, K>> selector)
    {
      if (selector.Body.NodeType != ExpressionType.MemberAccess)
      {
        throw new ArgumentException("A property selector expression has an incorrect format");
      }

      var memberAccess = selector.Body as MemberExpression;

      if (memberAccess.Member.MemberType != MemberTypes.Property)
      {
        throw new ArgumentException("A selected member is not a property");
      }

      return memberAccess.Member.Name;
    }

  }
}